﻿module poseidon.controller.debugcontrol.debugger;

class CDebugger
{
private:
	import dwt.all;
	import poseidon.controller.debugcontrol.debugPanel;
	import poseidon.controller.debugcontrol.watch;
	import poseidon.controller.debugcontrol.breakpoint;
	import poseidon.controller.debugcontrol.pipe;

	import poseidon.model.executer;
	import poseidon.model.misc;
	import poseidon.controller.gui;
	import poseidon.controller.edititem;
	import poseidon.controller.debugcontrol.debugparser;

	import poseidon.controller.dialog.generaldialog;
	SashForm					_parent;
	SashForm 					_brother;
	SashForm 					debugSash;
	
	CDebugItem					debugItem;
	CVariableItem				varItem;
	CBreakPointItem				bpItem;
	CRegisterItem				regItem;
	CStackItem					stackItem;
	CDllItem					dllItem;
	CPipe						pipe;

	bool						bStarted;

	void updateRegisters( char[][] regs ){ regItem.updateItems( regs );	}

	void updateStack( char[][] stacks )
	{
		stackItem.delAll();
		foreach( char[] s; stacks )
			if( s.length > 2 ) stackItem.add( s );
	}

	void listDll( char[][] dlls )
	{
		dllItem.delAll();
		foreach( char[] s; dlls )
		{
			char[][] baseAndName = std.string.split( s, " " );
			if( baseAndName.length > 1 ) 
				if( baseAndName[0] != "Name" && baseAndName[0] != "Base" ) dllItem.add( baseAndName );
		}
	}

	void updateVariables(){	varItem.updateVariables(); }


public:
	static bool		bShowOutPut = true;
	static bool 	bLiveUpdateVar;
	
	CWatchPanel 	topRightPanel;
	CVariableNode	variableBaseRoot;

	char[]			projectDir;
	
	this( SashForm parent )
	{
		debugSash = new SashForm( parent, DWT.HORIZONTAL | DWT.SMOOTH);

		TopPanel topLeftPanel = new TopPanel( debugSash );
		debugItem = topLeftPanel.debugItem;

		topRightPanel = new CWatchPanel( debugSash );
		varItem = topRightPanel.varItem;
		bpItem = topRightPanel.bpItem;
		regItem = topRightPanel.regItem;
		stackItem = topRightPanel.stackItem;
		dllItem	= topRightPanel.dllItem;

		debugSash.setWeights( [40, 60] );
	}

	~this()
	{
		if( pipe !is null ) delete pipe;

		bStarted = false;
		projectDir = "";
	}

	// GUI Function
	void hide( bool bTrue )
	{
		if( bTrue )
			debugSash.setMaximizedControl( _brother );
		//else
			//debugSash.setMaximizedControl( this );
	}

	void setBrotherSashForm( SashForm broSash ){ _brother = broSash; }

	void clear(){ debugItem.content.setText( "" ); }
	
	void setString( char[] str ){ if( bShowOutPut ) debugItem.content.setText( str ); }

	void appendString( char[] str ){ if( bShowOutPut ) debugItem.content.append( str ); }

	void appendLine( char[] str ){ if( bShowOutPut ) debugItem.content.append( str ~ "\n" ); }
	
	// Debug Function-------------------------------------------------------------------
	bool runDebug( ToolEntry entry, char[] _projectDir )
	{
		if( pipe is null )
		{
			if( sGUI.debugSash.getMaximizedControl() )
			{
				sGUI.debugSash.setMaximizedControl( null );
				sGUI.menuMan.viewDebugItem.setSelection( true );
			}

			try
			{
				pipe = new CPipe( entry );
				resetToolBar();
			}
			catch( Exception e )
			{
				MessageBox.showMessage( e.toString );
				return false;
			}
		}

		// We have Debug Items
		foreach( TableItem ti; bpItem.getAllItems() )
		{
			if( ti.getChecked() )
			{
				CBreakPoint bp = cast(CBreakPoint) ti.getData();
				pipe.sendCommand( "bp " ~ bp.fullPath ~ ":" ~ std.string.toString( bp.lineNum ) ~ "\n" );
			}
		}

		bStarted = true;
		projectDir = _projectDir;
		return true;
	}

	char[] write( char[] command, bool bShow = true )
	{
		if( pipe !is null ) return pipe.sendCommand( command, bShow );
		return null;
	}

	void read(){ if( pipe !is null ) pipe.readConsole(); }
	
	bool isPipeCreate(){ if( pipe is null ) return false;else return true; }

	void stop()
	{ 
		if( pipe !is null )
		{
			delete pipe;
			EditItem[] eis = cast(EditItem[]) sGUI.editor.getItems();
			// 刪掉所有的執行MARK
			foreach( EditItem ei; eis )
				ei.deleteAllDebugRunMarker();

			updateRegisters( null );
			stackItem.delAll();
			debugItem.txtCommandLine.setText( "" );
			if( sGUI.debuggerDMD.variableBaseRoot !is null ) delete sGUI.debuggerDMD.variableBaseRoot;
			varItem.updateVariables( true );

			bStarted = false;
		}
	}

	void consoleCommand()
	{
		if( !isPipeCreate()) return;
		
		//AskStringDlg dlg = new AskStringDlg( sShell, "Please Input Command", null );
		//dlg.setText( Globals.getTranslation( "RENAME" ) );
		//dlg.setText( "Debugger Command" );
		//dlg.setValidateDelegate( &_validate) ;
		char[] result = std.string.strip( debugItem.txtCommandLine.getText() );//std.string.strip( dlg.open() );

		if( result.length )
		{
			write( result ~ "\n" );
			debugItem.txtCommandLine.selectAll();
		}
	}
		
	void addBP_editor( char[] fullPath, int lineNum )
	{
		write( "bp " ~ fullPath ~ ":" ~ std.string.toString( lineNum ) ~ "\n" );
		bpItem.add( fullPath, lineNum );
	}
	
	void delBP_editor( char[] fullPath, int lineNum )
	{
		write( "dbp " ~ fullPath ~ ":" ~ std.string.toString( lineNum ) ~ "\n" );
		bpItem.del( fullPath, lineNum );
	}

	void resetToolBar()
	{
		debugItem.updateToolBar();
		regItem.updateToolBar();
		stackItem.updateToolBar();
		varItem.updateToolBar();
		dllItem.updateToolBar();
	}

	void step( int flag )
	{
		if( !isPipeCreate() || !bStarted ) return;
		
		char[] result;
		
		switch( flag )
		{
			case 0: // step into
				result = write( "in\n" );
				break;

			case 1: // step over
				result = write( "ov\n" );
				break;

			case 2: // step return
				result = write( "out\n" );
				break;

			default:
				return;
		}

		CDebugParser.step( result );
	}

	void dumpRegister()
	{
		if( !isPipeCreate() || !bStarted ) return;
		
		char[] result = write( "dr\n" );
		updateRegisters( CDebugParser.dumpRegister( result ) );
	}

	void dumpStack()
	{
		if( !isPipeCreate() || !bStarted ) return;
		
		char[] result = write( "ds\n" );
		updateStack( CDebugParser.dumpStack( result ) );
	}

	void dumpDll()
	{
		if( !isPipeCreate() || !bStarted ) return;
		
		char[] result = write( "ldll\n" );
		listDll( CDebugParser.listDlls( result ) );
	}

	void dumpVariables()
	{
		if( !isPipeCreate() || !bStarted ) return;
		
		char[] result = sGUI.debuggerDMD.write( "lsv\n" );
		CDebugParser.listVariables( result );
		updateVariables();
	}

	bool isRunning(){ return bStarted; }
}
